#include <aknutils.h>
#include <akndef.h>
#include "ContainerControl.h"
#include "Label.h"
#include "ListBox.h"

CContainerControl* CContainerControl::NewL(const TRect& aRect, const CCoeControl* aParent)
	{
	CContainerControl* self = CContainerControl::NewLC(aRect,aParent);
	CleanupStack::Pop(self);
	return self;
	}

CContainerControl* CContainerControl::NewLC(const TRect& aRect, const CCoeControl* aParent)
	{
	CContainerControl* self = new(ELeave) CContainerControl();
	CleanupStack::PushL(self);
	self->ConstructL(aRect,aParent);
	return self;
	}

CContainerControl::~CContainerControl()
	{
	Components().ResetAndDestroy();
	delete iBgContext;
	iBgContext = NULL;
	delete iScrollBarFrame;
	iScrollBarFrame = NULL;
	delete iBackGroundBitmap;
	iBackGroundBitmap = NULL;
	//iLog.CloseLog();
	//iLog.Close();
	}

CContainerControl::CContainerControl()
	{
	iBgContext = NULL;
	iScrollBarFrame = NULL;
	iFocusControl = NULL;
	iCurPos = 0;
	iMaxControlIndex = 0;
	iEnableSkin = ETrue;
	iBackGroundBitmap = NULL;
	iTotalHeight = 0;
	}

void CContainerControl::ConstructL(const TRect& aRect, const CCoeControl* aParent)
	{
	// No parent owner, so create an own window
    if(aParent == NULL)
        {
        CreateWindowL();
        }
    else
        {
        SetContainerWindowL(*aParent);
        }
    // Initialize component array
    InitComponentArrayL();

    // Creating Scroll Bars
    iScrollBarFrame = new ( ELeave ) CEikScrollBarFrame( this, NULL );
    iScrollBarFrame->CreateDoubleSpanScrollBarsL( ETrue, EFalse );
    iScrollBarFrame->SetTypeOfVScrollBar( CEikScrollBarFrame::EDoubleSpan );
    iScrollBarFrame->SetScrollBarVisibilityL( CEikScrollBarFrame::EOff,
    		CEikScrollBarFrame::EOff );
 
	iBgContext = CAknsBasicBackgroundControlContext::NewL(
		KAknsIIDQsnBgScreen,TRect(0,0,1,1), ETrue);
    SetRect(aRect);
    ActivateL();
	}

TKeyResponse CContainerControl::OfferKeyEventL(
		const TKeyEvent& aKeyEvent, TEventCode aType )
	{
	if ( iFocusControl != NULL
		&& iFocusControl->OfferKeyEventL( aKeyEvent, aType ) == EKeyWasConsumed )
		{
		return EKeyWasConsumed;
		}
	// Move focus
    switch ( aKeyEvent.iCode )
        {
        case EKeyUpArrow:
            {
            MoveFocusUpL();
            DrawNow(); // Draw components again
            return EKeyWasConsumed;
            }
        case EKeyDownArrow:
            {
            MoveFocusDownL();
            DrawNow(); // Draw components again
            return EKeyWasConsumed;
            }
        default:
            {
            return EKeyWasNotConsumed;
            }
        }
	}

void CContainerControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
	{
	switch (aPointerEvent.iType)
	       {
		   case TPointerEvent::EButton1Down:
		   case TPointerEvent::EButton2Down:
		   case TPointerEvent::EButton3Down:
			   {
				   iFirstPositionY = aPointerEvent.iPosition.iY;
				   CCoeControlArray::TCursor cursor = Components().Begin();
				   CCoeControl* ctrl = NULL;
				   while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
					   {
					   if (ctrl->Rect().Contains(aPointerEvent.iPosition))
						{
						if (ctrl->IsFocused())
							ctrl->HandlePointerEventL(aPointerEvent);
						else
							{
							iFocusControl->SetFocus(EFalse);
							iFocusControl = ctrl;
							iFocusControl->SetFocus(ETrue);
							}
						break;
						}
					   cursor.Next();
					   }
					
			   }
			   break;
           case TPointerEvent::EDrag:
        	   {
				if (iTotalHeight > Rect().Height())
					{
					if (aPointerEvent.iPosition.iY != iFirstPositionY)
						{
						UpdateControls(aPointerEvent.iPosition.iY - iFirstPositionY);
						iFirstPositionY = aPointerEvent.iPosition.iY;
						
						if (iFirstControl && iFirstControl->Position().iY > Rect().iTl.iY)
							{
							UpdateControls(Rect().iTl.iY - iFirstControl->Position().iY);
							}
						else if (iFirstControl && iFirstControl->Position().iY + iTotalHeight < Rect().iBr.iY)
							{
							UpdateControls(Rect().iBr.iY - iFirstControl->Position().iY - iTotalHeight);
							}
						}
					}
				}
        	   break;
	       }
	DrawNow();
	}

void CContainerControl::AddControlL(CCoeControl* aControl)
	{
	// NOTE: Transfer ownership of CCoeControl to CContainerControl
    // Add control into container control
    Components().AppendLC(aControl,iMaxControlIndex++);
    CleanupStack::Pop(aControl);

    // Focus first component
    if (Components().Count()== 1)
        {
        aControl->SetFocus(ETrue);
        iFocusControl = aControl;
        iFirstControl = aControl;
        }
	}

TTypeUid::Ptr CContainerControl::MopSupplyObject(TTypeUid aId)
	{
	if (iEnableSkin && iBgContext)
		{
		return MAknsControlContext::SupplyMopObject(aId, iBgContext);
		}
	return CCoeControl::MopSupplyObject(aId);
	}

void CContainerControl::Draw(const TRect& aRect) const
	{
	CWindowGc& gc = SystemGc();
	gc.Clear(aRect);
	gc.SetClippingRect(aRect);
	TRect rect = Rect();
	gc.SetBrushColor(KRgbRed);
	gc.DrawRect(aRect);
	// Redraw the background using the default skin
	if (iEnableSkin)
        {
        MAknsSkinInstance* skin = AknsUtils::SkinInstance();
        MAknsControlContext* cc = AknsDrawUtils::ControlContext( this );
        AknsDrawUtils::Background( skin, cc, this, gc, aRect );
        }
	else
        {
	    if (iBackGroundBitmap && iBackGroundBitmap->Bitmap())
             {
	         TRect bmpPieceRect(TPoint(0, 0), iBackGroundBitmap->SizeInPixels());
	        if (iBackGroundBitmap->MaskBitmap())
	             gc.DrawBitmapMasked(aRect,iBackGroundBitmap->Bitmap(),bmpPieceRect,iBackGroundBitmap->MaskBitmap(),EFalse);
	         else
	             gc.DrawBitmap(aRect, iBackGroundBitmap->Bitmap());
             }
        }
	gc.CancelClippingRect();
	}

void CContainerControl::SizeChanged()
	{
	CCoeControl::SizeChanged();
	TRect rect;
	if (iEnableSkin)
        {
        if (iBgContext)
            {
            AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EScreen, rect);
            iBgContext->SetRect(rect);
            if ( &Window() )
                {
                iBgContext->SetParentPos(TPoint(0, 0) );
                }
            }
        }

    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        static_cast< CBaseControl* >(ctrl)->SizeChanged(Rect());
        cursor.Next();
        }
	UpdateControls();
	}

void CContainerControl::HandleResourceChange(TInt aType)
	{
	TRect rect;
	if (iEnableSkin && aType==KEikDynamicLayoutVariantSwitch)
		{
		AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EMainPane, rect);
		SetRect(rect);
		}
	CCoeControl::HandleResourceChange(aType);
	}

void CContainerControl::MoveFocusUpL()
	{
	CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    CCoeControl* prevCtrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        if (ctrl->IsFocused())
            {
            if (prevCtrl)
                {
                TInt scroll = Min(Rect().Height() / 5,prevCtrl->Rect().Height());
                if (IsInRect(prevCtrl)
                		&& prevCtrl->Rect().iBr.iY - scroll > Rect().iTl.iY)
                	{
	                // Set focus to previous control
	                ctrl->SetFocus(EFalse);
	                prevCtrl->SetFocus(ETrue);
	                iFocusControl = prevCtrl;
	                iFocusedIndex--;
                	}
                else
                	{
                	UpdateControls(scroll);
                	}
                break;
                }
            else
                {
                if (ctrl->Rect().iTl.iY < Rect().iTl.iY)
                	{
                	TInt scroll = Min(Rect().Height() / 5,(Rect().iTl.iY - ctrl->Rect().iTl.iY + 2));
                	UpdateControls(scroll);
                	}
                break; // First control is already focused
                }
            }
        prevCtrl = ctrl;
        cursor.Next();
        }
	}

void CContainerControl::MoveFocusDownL()
	{
	CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    CCoeControl* nextCtrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        if (ctrl && ctrl->IsFocused())
            {
            cursor.Next();
            nextCtrl = cursor.Control<CCoeControl>();
            if (nextCtrl)
                {
                TInt scroll = Min(Rect().Height() / 5, nextCtrl->Rect().Height());
                if (IsInRect(nextCtrl)
                		&& nextCtrl->Rect().iTl.iY + scroll < Rect().iBr.iY)
                	{
	                // Set focus to next control
	                ctrl->SetFocus(EFalse);
	                nextCtrl->SetFocus(ETrue);
	                iFocusControl = nextCtrl;
	                iFocusedIndex++;
                	}
                else
                	{
                	if (nextCtrl->Rect().iBr.iY - Rect().iBr.iY > 0)
                		scroll = Min(scroll, nextCtrl->Rect().iBr.iY - Rect().iBr.iY + 2);
                	UpdateControls(-scroll);
                	}
                break;
                }
            else
                {
                if (ctrl->Rect().iBr.iY > Rect().iBr.iY)
                	{
                	TInt scroll = Min(Rect().Height() / 5,(ctrl->Rect().iBr.iY - Rect().iBr.iY));
                	UpdateControls(-scroll);
                	}
                break; // Last control is already focused
                }
            }
        cursor.Next();
        }
	}

void CContainerControl::UpdateControls(TInt aOffset, TBool aChangeCurPos)
	{
	TPoint position;
	iTotalHeight = 0;
    // Goes through all components of this container control
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = cursor.Control<CCoeControl>();
    if (ctrl)
    	position = ctrl->Position();
    position.iY += aOffset;
    if (aChangeCurPos)
    	iCurPos -= aOffset;

    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        // Set position
        ctrl->SetPosition(position);

        if ( IsInRect(ctrl) )
            {
            ctrl->MakeVisible(ETrue);
            }
        else
            {
            ctrl->MakeVisible(EFalse);
            }
        // Calculate position
        position.iY += ctrl->Rect().Height();
        iTotalHeight += ctrl->Size().iHeight;
        cursor.Next();
        }
    UpdateScrollBarFrameL();
	}

void CContainerControl::setEnableSkin(TBool aEnable)
    {
    iEnableSkin = aEnable;
    }

void CContainerControl::SetBackGroundBitmap(CImage* aImage)
    {
    delete iBackGroundBitmap;
    iBackGroundBitmap = NULL;
    iBackGroundBitmap = aImage;
    }

void CContainerControl::UpdateScrollBarFrameL()
	{
	TInt totalHeight = 0; // Height of the controls
    TInt height = 0; // This view height
    iShowScrollBar = EFalse;
    // Calculate components height
    CCoeControlArray::TCursor cursor = Components().Begin();
    CCoeControl* ctrl = NULL;
    while ((ctrl = cursor.Control<CCoeControl>()) != NULL)
        {
        totalHeight += ctrl->Size().iHeight;
        cursor.Next();
        }

    // This view height
    height = Rect().Height();

    // Set teh scrollbar visible if fields do not fit the screen
    if( totalHeight > height &&
         iScrollBarFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOff)
        {
        iScrollBarFrame->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff, // horizontal
                CEikScrollBarFrame::EOn); // vertical
        iShowScrollBar = ETrue;
        }
    // Hide the scrollbar if fields fit the screen
    else if ( totalHeight <= height &&
              iScrollBarFrame->VScrollBarVisibility() == CEikScrollBarFrame::EOn)
        {
        iScrollBarFrame->SetScrollBarVisibilityL(
                CEikScrollBarFrame::EOff, // horizontal
                CEikScrollBarFrame::EOff); // vertical
        }
    if (totalHeight <= height)
    	return ;
    // Update scroll bar position
    //iVDsSbarModel.SetScrollSpan(Components().Count());
    iVDsSbarModel.SetScrollSpan(totalHeight - height);
    TInt ws = Max(2,height * (totalHeight - height) / (totalHeight));
    iVDsSbarModel.SetWindowSize(ws);
    //iVDsSbarModel.SetFocusPosition(iFocusedIndex);
    iVDsSbarModel.SetFocusPosition(iCurPos);
    TEikScrollBarFrameLayout layout;
    layout.iTilingMode = TEikScrollBarFrameLayout::EInclusiveRectConstant;
    TRect rect = Rect();
    iScrollBarFrame->TileL(&iHDsSbarModel,&iVDsSbarModel,rect,rect,layout);
    iScrollBarFrame->SetVFocusPosToThumbPos(iVDsSbarModel.FocusPosition());
	}

TBool CContainerControl::IsInRect(CCoeControl* aCtrl)
	{
	if (aCtrl && (Rect().Contains(aCtrl->Position()) || Rect().iTl.iY < aCtrl->Rect().iBr.iY))
		return ETrue;
	else
		return EFalse;
	}
